﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Configuration;
using System.Security.Cryptography;

namespace Ashwani.Cryptography.Signature
{
    public class MachineKeySignatureProvider : ISignatureProvider
    {
        enum HashMode
        {
            HMACSHA1,
            HMACMD5,
        }


        HashMode _hashMode = HashMode.HMACSHA1;
        byte[] _validationKey;
        public MachineKeySignatureProvider()
        {
            MachineKeySection section;

            if (HostingEnvironment.IsHosted)
            {
                if (HostingEnvironment.ApplicationVirtualPath != null)
                    section = (MachineKeySection)WebConfigurationManager.GetSection("system.web/machineKey", HostingEnvironment.ApplicationVirtualPath);
                else
                    section = (MachineKeySection)WebConfigurationManager.GetSection("system.web/machineKey");
            }
            else
            {
                section = (MachineKeySection)ConfigurationManager.GetSection("system.web/machineKey");
            }

            if (section != null)
            {
                string validation = section.Validation == null ? string.Empty : section.Validation.ToString().ToLowerInvariant();
                string validationKey = section.ValidationKey == null ? string.Empty : section.ValidationKey;

                switch (validation)
                {
                    case @"md5":
                        _hashMode = HashMode.HMACMD5;
                        break;
                }

                if (_hashMode == HashMode.HMACSHA1)
                {
                    if (validationKey.Length < 128)
                        throw new InvalidOperationException("Insufficient MachineKey.ValidationKey material supplied");

                    _validationKey = DecodeHex(validationKey);
                }
                else if (_hashMode == HashMode.HMACMD5)
                {
                    if (validationKey.Length < 128)
                        throw new InvalidOperationException("Insufficient MachineKey.ValidationKey material supplied");

                    _validationKey = DecodeHex(validationKey);
                }
            }
        }


        private byte[] DecodeHex(string hexString)
        {
            byte[] bytes = new byte[hexString.Length >> 1];

            for (int i = 0; i < bytes.Length; i++)
                bytes[i] = Convert.ToByte(hexString.Substring(i << 1, 2), 16);

            return bytes;
        }

        public byte[] CreateSignature(byte[] plaintext)
        {
           
            KeyedHashAlgorithm algorithm;

            switch (_hashMode)
            {

                case HashMode.HMACMD5:

                    algorithm = new HMACMD5(_validationKey);
                    return new SignatureCryptographer(algorithm).CreateSignature(plaintext);
                default:
                    algorithm = new HMACSHA1(_validationKey, true);
                    return new SignatureCryptographer(algorithm).CreateSignature(plaintext);
            }
        }




        public bool CompareSignature(byte[] plaintext, byte[] hashedtext)
        {
           

            KeyedHashAlgorithm algorithm;
            switch (_hashMode)
            {
                case HashMode.HMACMD5:
                    algorithm = new HMACMD5(_validationKey);
                    return new SignatureCryptographer(algorithm).CompareSignature(plaintext, hashedtext);
                default:
                    algorithm = new HMACSHA1(_validationKey, true);
                    return new SignatureCryptographer(algorithm).CompareSignature(plaintext, hashedtext);
            }
        }


        #region ISignatureProvider Members


        public byte[] CreateSignature(byte[] plaintext, byte[] validationKey)
        {
            throw new NotImplementedException();
        }

        public bool CompareSignature(byte[] plaintext, byte[] hashedtext, byte[] validationKey)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
